import 'dart:math';
import 'package:flutter_frame/app/core/core.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

///http://www.loongwind.com/archives/376.html#more
class RabbitPainter extends CustomPainter {
  RabbitPainter({required this.bodyAnimation});

  final Animation bodyAnimation;

  late final Paint _paint = Paint()
    ..strokeWidth = 6.w
    ..color = const Color(0xff000000)
    ..style = PaintingStyle.stroke;

  @override
  void paint(Canvas canvas, Size size) async {
    //左侧身体轮廓
    List<Offset> createLeftBodyPoints() {
      final position1 = Offset(110.w, 100.w);
      final position2 = Offset(30.w, position1.dy + 20.w);
      final position3 = Offset(40.w, position2.dy + 100.w);
      final position4 = Offset(110.w, position3.dy + 10.w);

      final position5 = Offset(50.w, position4.dy + 20.w);
      final position6 = Offset(60.w, position5.dy + 80.w);
      final position7 = Offset(125.w, position6.dy + 10.w);

      return [
        position1,
        position2,
        position3,
        position4,
        position5,
        position6,
        position7
      ];
    }

    final leftBodyPoints = createLeftBodyPoints();
    final leftBodyPath = createThreePath(leftBodyPoints);

    //右侧身体轮廓
    final matrix4 = Matrix4.translationValues(0.8.sw, 0, 0);
    matrix4.rotateY(2 * pi / 2);
    final rightBodyPath = leftBodyPath.transform(matrix4.storage);

    //耳朵轮廓
    final leftFirstPosition = leftBodyPath.getPositionFromPercent(0.008);
    final rightFirstPosition = rightBodyPath.getPositionFromPercent(0.008);

    final centerWidth = rightFirstPosition.dx - leftFirstPosition.dx;

    final position1 = Offset(leftFirstPosition.dx, leftFirstPosition.dy);
    final position2 = Offset(leftFirstPosition.dx - 50.w, -20.w);
    final position3 = Offset(leftFirstPosition.dx + centerWidth / 2, -20.w);
    final position4 =
        Offset(leftFirstPosition.dx + centerWidth / 2, leftFirstPosition.dy);
    final position5 =
        Offset(leftFirstPosition.dx + centerWidth / 2 + 5.w, -12.w);
    final position6 = Offset(rightFirstPosition.dx + 55.w, -12.w);
    final position7 = Offset(rightFirstPosition.dx, rightFirstPosition.dy);

    final points = [
      position1,
      position2,
      position3,
      position4,
      position5,
      position6,
      position7
    ];

    final earPath = createThreePath(points);

    //左侧手脚
    final handsFeetPosition1 =
        Offset(leftBodyPoints[3].dx + 10.w, leftBodyPoints[3].dy + 10.w);
    final handsFeetPosition2 =
        Offset(handsFeetPosition1.dx + 20.w, handsFeetPosition1.dy + 5.w);
    final handsFeetPosition3 =
        Offset(handsFeetPosition2.dx + 20.w, handsFeetPosition2.dy + 40.w);
    final handsFeetPosition4 =
        Offset(handsFeetPosition1.dx, handsFeetPosition3.dy + 15.w);

    final handsFeetPosition5 =
        Offset(handsFeetPosition4.dx + 20.w, handsFeetPosition4.dy + 10.w);
    final handsFeetPosition6 =
        Offset(handsFeetPosition5.dx + 10.w, handsFeetPosition5.dy + 20.w);
    final handsFeetPosition7 =
        Offset(leftBodyPoints.last.dx, leftBodyPoints.last.dy);
    final leftHandsFeetPoints = [
      handsFeetPosition1,
      handsFeetPosition2,
      handsFeetPosition3,
      handsFeetPosition4,
      handsFeetPosition5,
      handsFeetPosition6,
      handsFeetPosition7,
    ];

    final leftHandsFeetPath = createThreePath(leftHandsFeetPoints);

    //右侧手脚
    final rightHandsFeetPosition1 =
        Offset(leftBodyPoints[3].dx + 80.w, leftBodyPoints[3].dy + 15.w);
    final rightHandsFeetPosition2 = Offset(
        rightHandsFeetPosition1.dx - 20.w, rightHandsFeetPosition1.dy + 5.w);
    final rightHandsFeetPosition3 = Offset(
        rightHandsFeetPosition2.dx - 15.w, rightHandsFeetPosition2.dy + 30.w);
    final rightHandsFeetPosition4 = Offset(
        rightHandsFeetPosition1.dx - 15.w, rightHandsFeetPosition3.dy + 15.w);

    final rightHandsFeetPosition5 = Offset(
        rightHandsFeetPosition4.dx - 15.w, rightHandsFeetPosition4.dy + 10.w);
    final rightHandsFeetPosition6 = Offset(
        rightHandsFeetPosition5.dx - 5.w, rightHandsFeetPosition5.dy + 20.w);

    final rightLastPosition = rightBodyPath.getPositionFromPercent(1);
    final rightHandsFeetPosition7 =
        Offset(rightLastPosition.dx, rightLastPosition.dy);

    final rightHandsFeetPoints = [
      rightHandsFeetPosition1,
      rightHandsFeetPosition2,
      rightHandsFeetPosition3,
      rightHandsFeetPosition4,
      rightHandsFeetPosition5,
      rightHandsFeetPosition6,
      rightHandsFeetPosition7,
    ];
    final rightHandsFeetPath = createThreePath(rightHandsFeetPoints);

    //萝卜叶子的 “3” 以左右两边的手脚路径的起点作为参考点进行一定单位的便宜，绘制效果如下：
    final point1 = Offset(leftHandsFeetPoints.first.dx + 20.w,
        leftHandsFeetPoints.first.dy - 5.w);
    final point2 = Offset(leftHandsFeetPoints.first.dx - 5.w,
        leftHandsFeetPoints.first.dy - 45.w);
    final point3 = Offset(leftHandsFeetPoints.first.dx + 45.w,
        leftHandsFeetPoints.first.dy - 45.w);
    final point4 = Offset(leftHandsFeetPoints.first.dx + 35.w,
        leftHandsFeetPoints.first.dy - 10.w);
    final point5 = Offset(leftHandsFeetPoints.first.dx + 40.w,
        leftHandsFeetPoints.first.dy - 35.w);
    final point6 = Offset(
        rightFirstPosition.dx + 0.w, leftHandsFeetPoints.first.dy - 35.w);
    final point7 = Offset(leftHandsFeetPoints.first.dx + 50.w,
        leftHandsFeetPoints.first.dy - 5.w);

    final points2 = [point1, point2, point3, point4, point5, point6, point7];
    final Path radishLeafPath = createThreePath(points2);

    //嘴巴
    final radishHeadMinYPosition = radishLeafPath.getMinYPosition();
    final mouthPosition1 = Offset(
        radishHeadMinYPosition.dx - 10.w, radishHeadMinYPosition.dy - 20.w);
    final mouthPosition2 =
        Offset(mouthPosition1.dx - 2.w, mouthPosition1.dy + 10.w);
    final mouthPosition3 =
        Offset(mouthPosition2.dx + 18.w, mouthPosition2.dy + 5.w);
    final mouthPosition4 =
        Offset(mouthPosition3.dx + 2.w, mouthPosition1.dy + 2.w);

    final mouthPosition5 = Offset(mouthPosition4.dx, mouthPosition4.dy + 10.w);
    final mouthPosition6 =
        Offset(mouthPosition5.dx + 18.w, mouthPosition5.dy + 2.w);
    final mouthPosition7 = Offset(mouthPosition6.dx + 2.w, mouthPosition1.dy);
    final mouthPoints = [
      mouthPosition1,
      mouthPosition2,
      mouthPosition3,
      mouthPosition4,
      mouthPosition5,
      mouthPosition6,
      mouthPosition7,
    ];
    final mouthPath = createThreePath(mouthPoints);

    //眼睛不是 “3” 了，只需要使用二次贝塞尔曲线就行了，代码如下：
    final leftEyesPoint1 =
        Offset(leftBodyPoints.first.dx - 5.w, leftBodyPoints.first.dy + 50.w);
    final leftEyesPoint2 =
        Offset(leftEyesPoint1.dx + 10.w, leftEyesPoint1.dy - 13.w);
    final leftEyesPoint3 = Offset(leftEyesPoint1.dx + 20.w, leftEyesPoint1.dy);
    final Path leftEyesPath = Path();
    leftEyesPath.moveToPoint(leftEyesPoint1);
    leftEyesPath.quadraticBezierTo(leftEyesPoint2.dx, leftEyesPoint2.dy,
        leftEyesPoint3.dx, leftEyesPoint3.dy);

    final rightEyesPoint1 =
        Offset(rightFirstPosition.dx - 15.w, rightFirstPosition.dy + 50.w);
    final rightEyesPoint2 =
        Offset(rightEyesPoint1.dx + 10.w, rightEyesPoint1.dy - 13.w);
    final rightEyesPoint3 =
        Offset(rightEyesPoint1.dx + 20.w, rightEyesPoint1.dy);

    final Path rightEyesPath = Path();

    rightEyesPath.moveToPoint(rightEyesPoint1);
    rightEyesPath.quadraticBezierTo(rightEyesPoint2.dx, rightEyesPoint2.dy,
        rightEyesPoint3.dx, rightEyesPoint3.dy);

    //画胡萝卜
    //胡萝卜顶部曲线也是使用三次贝塞尔曲线进行绘制，起始点为左边手脚的路径的 0.07 位置的点，
    // 通过 getPositionFromPercent 获取到具体点位坐标，其结束点为右边手脚路径的 0.07 位置
    //与左边对称。两个曲线控制点已胡萝卜叶的起始点和结束点作为参照进行一定单位的偏移，最终实现效果如下
    final radishTopPath = Path();
    final radishTopPosition1 = leftHandsFeetPath.getPositionFromPercent(0.07);
    final radishTopPosition2 =
        radishLeafPath.getPositionFromPercent(0).translate(0, -6.w);
    final radishTopPosition3 =
        radishLeafPath.getPositionFromPercent(1).translate(0, -9.w);
    final radishTopPosition4 = rightHandsFeetPath.getPositionFromPercent(0.07);

    radishTopPath.moveToPoint(radishTopPosition1);
    radishTopPath.cubicToPoints(
        [radishTopPosition2, radishTopPosition3, radishTopPosition4]);

    //底部接下来看底部曲线的绘制，实现思路与顶部曲线一致，不过底部采用的不是三次贝塞尔曲线，
    // 而是二次贝塞尔曲线，以左右手脚路径上指定点（路径上 0.9 位置）
    // 作为底部曲线的起始和结束点，曲线控制点以起始点坐标进行一定单位的偏移，代码实现如下
    final radishBottomPath = Path();
    final radishBottomPosition1 = leftHandsFeetPath.getPositionFromPercent(0.9);
    final radishBottomPosition2 = Offset(
        radishBottomPosition1.dx + 18.w, radishBottomPosition1.dy + 40.w);
    final radishBottomPosition3 =
        rightHandsFeetPath.getPositionFromPercent(0.9);

    radishBottomPath.moveToPoint(radishBottomPosition1);
    radishBottomPath.quadraticBezierTo(
        radishBottomPosition2.dx,
        radishBottomPosition2.dy,
        radishBottomPosition3.dx,
        radishBottomPosition3.dy);

    //画胡萝卜点缀
    final radishBodyPath1 = Path();
    final radishBodyPosition1 = leftHandsFeetPath.getPositionFromPercent(0.3);
    final radishBodyPosition2 =
        Offset(radishBodyPosition1.dx + 5.w, radishBodyPosition1.dy - 3.w);
    final radishBodyPosition3 =
        Offset(radishBodyPosition2.dx + 10.w, radishBodyPosition1.dy + 3.w);
    radishBodyPath1.moveToPoint(radishBodyPosition1);
    radishBodyPath1.quadraticBezierTo(radishBodyPosition2.dx,
        radishBodyPosition2.dy, radishBodyPosition3.dx, radishBodyPosition3.dy);

    final radishBodyPath2 = Path();
    final radishBodyPosition4 = rightHandsFeetPath.getPositionFromPercent(0.7);
    final radishBodyPosition5 =
        Offset(radishBodyPosition4.dx - 5.w, radishBodyPosition4.dy - 3.w);
    final radishBodyPosition6 =
        Offset(radishBodyPosition5.dx - 10.w, radishBodyPosition5.dy + 3.w);
    radishBodyPath2.moveToPoint(radishBodyPosition4);
    radishBodyPath2.quadraticBezierTo(radishBodyPosition5.dx,
        radishBodyPosition5.dy, radishBodyPosition6.dx, radishBodyPosition6.dy);

    final radishBodyPath3 = Path();
    final radishBodyPosition7 = rightHandsFeetPath.getPositionFromPercent(0.78);
    final radishBodyPosition8 =
        Offset(radishBodyPosition7.dx - 3.w, radishBodyPosition7.dy - 3.w);
    final radishBodyPosition9 =
        Offset(radishBodyPosition8.dx - 5.w, radishBodyPosition8.dy + 3.w);
    radishBodyPath3.moveToPoint(radishBodyPosition7);
    radishBodyPath3.quadraticBezierTo(radishBodyPosition8.dx,
        radishBodyPosition8.dy, radishBodyPosition9.dx, radishBodyPosition9.dy);

    //尾巴 是一个三阶贝塞尔曲线
    final tailPath = Path();
    final tailPosition1 = rightBodyPath.getPositionFromPercent(0.8);
    final tailPosition2 =
        Offset(tailPosition1.dx + 35.w, tailPosition1.dy - 30.w);
    final tailPosition3 =
        Offset(tailPosition1.dx + 35.w, tailPosition1.dy + 40.w);
    final tailPosition4 = rightBodyPath.getPositionFromPercent(0.9);

    tailPath.moveToPoint(tailPosition1);
    tailPath.cubicToPoints([tailPosition2, tailPosition3, tailPosition4]);

    //颜色填充部分
    final bodyBorderPath = Path();
    final positionFromPathPercent = earPath.getPositionFromPercent(0);
    bodyBorderPath
      ..moveTo(positionFromPathPercent.dx, positionFromPathPercent.dy)
      ..addPointsFromPath(earPath)
      ..addPointsFromPath(rightBodyPath)
      ..addPointsFromPath(rightHandsFeetPath.getPathFromPercent(0.9, 1),
          isReverse: true)
      ..addPointsFromPath(radishBottomPath, isReverse: true)
      ..addPointsFromPath(leftHandsFeetPath.getPathFromPercent(0.9, 1))
      ..addPointsFromPath(leftBodyPath, isReverse: true)
      ..addPath(tailPath, Offset.zero)
      ..close();
    final Paint paint2 = Paint()
      ..color = Colors.white
      ..style = PaintingStyle.fill; //画笔

    //身体上色操作
    canvas.drawPath(bodyBorderPath, paint2);
    //胡萝卜上色
    final Path radishBorderPath = Path();
    final radishFistPosition = radishTopPath.getPositionFromPercent(0);
    radishBorderPath
      ..moveTo(radishFistPosition.dx, radishFistPosition.dy)
      ..addPointsFromPath(radishTopPath)
      ..addPointsFromPath(rightHandsFeetPath)
      ..addPointsFromPath(radishBottomPath, isReverse: true)
      ..addPointsFromPath(leftHandsFeetPath, isReverse: true)
      ..close();
    paint2.color = Colors.orange;
    canvas.drawPath(radishBorderPath, paint2);
    //胡萝卜 上色
    paint2.color = Colors.green;
    canvas.drawPath(radishLeafPath, paint2);

    paint2.color = const Color(0xFFE79EC3);

    /// 左耳填充
    canvas.save();
    final leftEarRect = Rect.fromLTWH(
        leftFirstPosition.dx - 3.w, 25.w, 30.w, (leftFirstPosition.dy - 30.w));
    canvas.translate(leftEarRect.center.dx, leftEarRect.center.dy);
    Path leftEarPath = Path();
    leftEarPath.addOval(Rect.fromLTWH(-leftEarRect.width / 2,
        -leftEarRect.height / 2, leftEarRect.width, leftEarRect.height));

    leftEarPath = leftEarPath.transform(Matrix4.rotationZ(-pi / 15).storage);
    canvas.drawPath(leftEarPath, paint2);
    canvas.restore();

    /// 右耳填充
    canvas.save();
    final rightEarRect = Rect.fromLTWH(rightFirstPosition.dx - 23.w, 25.w, 30.w,
        (rightFirstPosition.dy - 30.w));
    canvas.translate(rightEarRect.center.dx, rightEarRect.center.dy);

    Path rightEarPath = Path();
    rightEarPath.addOval(Rect.fromLTWH(-rightEarRect.width / 2,
        -rightEarRect.height / 2, rightEarRect.width, rightEarRect.height));
    rightEarPath = rightEarPath.transform(Matrix4.rotationZ(pi / 10).storage);
    canvas.drawPath(rightEarPath, paint2);
    canvas.restore();

    // 腮红
    Path leftFacePath = Path();
    Rect leftFaceRect = Rect.fromLTWH(
        position1.dx - 25.w - 15.w, position1.dy + 80.w - 15.w, 30.w, 30.w);
    leftFacePath.addOval(leftFaceRect);
    canvas.drawPath(leftFacePath, paint2);

    Path rightFacePath = Path();
    Rect rightFaceRect = Rect.fromLTWH(rightFirstPosition.dx + 25.w - 15.w,
        rightFirstPosition.dy + 80.w - 15.w, 30.w, 30.w);
    rightFacePath.addOval(rightFaceRect);
    canvas.drawPath(rightFacePath, paint2);

    // //身体图案绘制
    // canvas.drawPath(leftBodyPath, paint);
    // canvas.drawPath(tailPath, paint);
    // canvas.drawPath(earPath, paint);
    // canvas.drawPath(rightBodyPath, paint);
    // //左侧手脚绘制
    // canvas.drawPath(leftHandsFeetPath, paint);
    // //右侧手脚绘制
    // canvas.drawPath(rightHandsFeetPath, paint);
    // //嘴巴绘制
    // canvas.drawPath(mouthPath, paint);
    // //眼睛绘制
    // canvas.drawPath(leftEyesPath, paint);
    // canvas.drawPath(rightEyesPath, paint);
    // //胡萝卜 图像绘制
    // canvas.drawPath(radishLeafPath, paint);
    // canvas.drawPath(radishBottomPath, paint);
    // canvas.drawPath(radishTopPath, paint);
    // canvas.drawPath(radishBodyPath1, paint);
    // canvas.drawPath(radishBodyPath2, paint);
    // canvas.drawPath(radishBodyPath3, paint);

    // 将所有线条path放入集合进行统一绘制
    final list = [
      leftBodyPath,
      rightBodyPath,
      earPath,
      leftHandsFeetPath,
      rightHandsFeetPath,
      radishLeafPath,
      mouthPath,
      leftEyesPath,
      rightEyesPath,
      radishTopPath,
      radishBottomPath,
      radishBodyPath1,
      radishBodyPath2,
      radishBodyPath3,
      tailPath,
    ];

    /// 绘制所有边框
    drawBorder(canvas, list);
  }

  ///绘制整体边框动画
  void drawBorder(Canvas canvas, List<Path> list) {
    final int index = (bodyAnimation.value as double) ~/ 1;
    final double progress = (bodyAnimation.value as double) % 1;
    for (int i = 0; i < index; i++) {
      final path = list[i];
      canvas.drawPath(path, _paint);
    }
    if (index >= list.length) {
      return;
    }
    final path = list[index];
    final pms = path.computeMetrics();
    final pm = pms.first;
    canvas.drawPath(pm.extractPath(0, progress * pm.length), _paint);
  }

  /// 创建3形状的path
  Path createThreePath(List<Offset> points) {
    final Path path = Path();
    path.moveToPoint(points[0]);
    path.cubicToPoints(points.sublist(1, 4));
    path.cubicToPoints(points.sublist(4, 7));
    return path;
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    //是否需要重新绘制
    return true;
  }
}

//自定义扩展 Path 的方法
extension PathExt on Path {
  void moveToPoint(Offset point) {
    moveTo(point.dx, point.dy);
  }

  void cubicToPoints(List<Offset> points) {
    if (points.length != 3) {
      throw "params points length must 3";
    }
    // 三阶贝塞尔曲线
    cubicTo(points[0].dx, points[0].dy, points[1].dx, points[1].dy,
        points[2].dx, points[2].dy);
  }

  Offset getPositionFromPercent(double percent) {
    final pms = computeMetrics();
    final pm = pms.first;
    final position =
        pm.getTangentForOffset(pm.length * percent)?.position ?? Offset.zero;
    return position;
  }

  Offset getMinYPosition() {
    final pms = computeMetrics();
    final pm = pms.first;
    var minPosition = pm.getTangentForOffset(0)?.position;
    for (int i = 0; i < pm.length; i++) {
      final position = pm.getTangentForOffset(i.toDouble())?.position;
      if (minPosition == null ||
          (position != null && position.dy < minPosition.dy)) {
        minPosition = position;
      }
    }
    return minPosition ?? Offset.zero;
  }

  void addPointsFromPath(Path copyPath, {bool isReverse = false}) {
    final pms = copyPath.computeMetrics();
    final pm = pms.first;
    if (isReverse) {
      for (double i = pm.length; i > 0; i--) {
        final position = pm.getTangentForOffset(i.toDouble())?.position;
        if (position != null) {
          lineTo(position.dx, position.dy);
        }
      }
    } else {
      for (int i = 0; i < pm.length; i++) {
        final position = pm.getTangentForOffset(i.toDouble())?.position;
        if (position != null) {
          lineTo(position.dx, position.dy);
        }
      }
    }
  }

  Path getPathFromPercent(double startPercent, double endPercent) {
    final pms = computeMetrics();
    final pm = pms.first;
    final resultPath =
        pm.extractPath(pm.length * startPercent, pm.length * endPercent);
    return resultPath;
  }
}
